<?php

namespace pmvc\annotation;

use PHPUnit_Framework_TestCase;
use Exception;
use stdClass;

class AnnotationLexerTest
	extends PHPUnit_Framework_TestCase {

	public function testNextToken1() {

		// sample annotation string
		$str = '
		
		/**
		 * This is some text
		 *
		 * @\Annotation(
		 *		int=1,
		 *		float=1.1,
		 *		bool=true,
		 *		string="a \"string\"",
		 *		string2=\'a "string2"\',
		 *		annotation=@\Annotation2(),
		 *		const=SomeClass::CONSTANT,
		 *		array=[Another::CONST, YetAnother::CONSTANT]
		 *	)
		 */
		 
		 ';

		$expected = Array();
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "int");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "float");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_FLOAT, "1.1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "bool");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_BOOL, "true");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "string");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_STRING, "\"a \\\"string\\\"\"");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "string2");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_STRING, "'a \"string2\"'");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "annotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation2");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "const");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_CONST, "SomeClass::CONSTANT");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "array");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_CONST, "Another::CONST");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_CONST, "YetAnother::CONSTANT");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");

		// create lexer
		$lexer = new AnnotationLexer($str);

		// consume all tokens
		$tokens = Array();
		while (($token=$lexer->nextToken())!==false) {
			$tokens []= $token;
		}

		for ($i=0; $i<count($tokens); $i++) {
			$this->assertEquals($expected[$i]["type"], $tokens[$i]->type, "type missmatch: ".$expected[$i]["type"]." != ".$tokens[$i]->type);
			$this->assertEquals($expected[$i]["value"], $tokens[$i]->value, "value missmatch: ".$expected[$i]["value"]." != ".$tokens[$i]->value);
		}
	}

	public function testNextToken2() {

		// sample annotation string
		$str = '
		
		/**
		 * This is some text
		 *
		 * @\Annotation(
		 *		int=1,
		 *		float=1.1,
		 *		bool=true,
		 *		string="a \"string\"",
		 *		annotation=@\Annotation2(sub="value", bool=false, wut=@\Annotation3()),
		 *		woot=69.187
		 *	)
		 */
		 
		 ';

		$expected = Array();
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "int");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "float");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_FLOAT, "1.1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "bool");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_BOOL, "true");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "string");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_STRING, "\"a \\\"string\\\"\"");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "annotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation2");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "sub");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_STRING, "\"value\"");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "bool");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_BOOL, "false");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "wut");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation3");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "woot");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_FLOAT, "69.187");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");

		// create lexer
		$lexer = new AnnotationLexer($str);

		// consume all tokens
		$tokens = Array();
		while (($token=$lexer->nextToken())!==false) {
			$tokens []= $token;
		}

		for ($i=0; $i<count($tokens); $i++) {
			$this->assertEquals($expected[$i]["type"], $tokens[$i]->type, "type missmatch: ".$expected[$i]["type"]." != ".$tokens[$i]->type);
			$this->assertEquals($expected[$i]["value"], $tokens[$i]->value, "value missmatch: ".$expected[$i]["value"]." != ".$tokens[$i]->value);
		}
	}

	public function testNextToken_Array() {

		// sample annotation string
		$str = '
		
		/**
		 * This is some text
		 *
		 * @\Annotation(ints=[1, 2, 3])
		 */
		 
		 ';

		$expected = Array();
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "ints");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "2");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "3");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");

		// create lexer
		$lexer = new AnnotationLexer($str);

		// consume all tokens
		$tokens = Array();
		while (($token=$lexer->nextToken())!==false) {
			$tokens []= $token;
		}

		for ($i=0; $i<count($tokens); $i++) {
			$this->assertEquals($expected[$i]["type"], $tokens[$i]->type, "type missmatch: ".$expected[$i]["type"]." != ".$tokens[$i]->type);
			$this->assertEquals($expected[$i]["value"], $tokens[$i]->value, "value missmatch: ".$expected[$i]["value"]." != ".$tokens[$i]->value);
		}
	}

	public function testNextToken_ArrayComplex() {

		// sample annotation string
		$str = '
		
		/**
		 * This is some text
		 *
		 * @\Annotation(ints=[1, @\Wow(), 3])
		 */
		 
		 ';

		$expected = Array();
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Annotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "ints");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "Wow");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "3");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");

		// create lexer
		$lexer = new AnnotationLexer($str);

		// consume all tokens
		$tokens = Array();
		while (($token=$lexer->nextToken())!==false) {
			$tokens []= $token;
		}

		for ($i=0; $i<count($tokens); $i++) {
			$this->assertEquals($expected[$i]["type"], $tokens[$i]->type, "type missmatch: ".$expected[$i]["type"]." != ".$tokens[$i]->type);
			$this->assertEquals($expected[$i]["value"], $tokens[$i]->value, "value missmatch: ".$expected[$i]["value"]." != ".$tokens[$i]->value);
		}
	}

	public function testNextToken_Arrays() {

		// sample annotation string
		$str = '
		
		/**
		 * This is garbage
		 * @\SomeAnnotation(x=[1,[21, 22, [231, 232], 24], [31, 32]])
		 */
		 
		 ';

		$expected = Array();
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_CLASS, "SomeAnnotation");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_NAME, "x");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "1");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "21");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "22");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "231");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "232");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "24");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_START, "[");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "31");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_INT, "32");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_VAR_ARRAY_END, "]");
		$expected []= $this->createExpectedToken(AnnotationLexer::TOKEN_ANNOTATION_FINISHED, ")");

		// create lexer
		$lexer = new AnnotationLexer($str);

		// consume all tokens
		$tokens = Array();
		while (($token=$lexer->nextToken())!==false) {
			$tokens []= $token;
		}
	

		for ($i=0; $i<count($tokens); $i++) {
			$this->assertEquals($expected[$i]["type"], $tokens[$i]->type, "type missmatch: ".$expected[$i]["type"]." != ".$tokens[$i]->type);
			$this->assertEquals($expected[$i]["value"], $tokens[$i]->value, "value missmatch: ".$expected[$i]["value"]." != ".$tokens[$i]->value);
		}
	}

	private function createExpectedToken($type, $value) {
		return Array("type"	=> $type,"value"=> $value);
	}

}

?>